package service

import (
	"context"
	"fmt"
	"fx_swift_ifcgate_agent/api"
	"fx_swift_ifcgate_agent/internal/model"
	"fx_swift_ifcgate_agent/pkg/code"
	"fx_swift_ifcgate_agent/pkg/global"
	"fx_swift_ifcgate_agent/pkg/internalerrors"
	"fx_swift_ifcgate_agent/pkg/logger"
	"fx_swift_ifcgate_agent/pkg/page"
	"github.com/gogf/gf/v2/container/gvar"
	"github.com/gogf/gf/v2/frame/g"
	"github.com/spf13/cast"
)

type ICommissionSrv interface {
	// 分佣列表
	CommissionList(ctx context.Context, req *api.CommissionListReq) (*page.Collection[*api.CommissionListRes], error)

	// 代理商佣金账户
	AgentCommissionAccount(ctx context.Context) ([]*api.AgentCommissionAccountRes, error)

	// 提现操作
	WithdrawOperator(ctx context.Context, req *api.WithdrawOperatorReq) error

	// 提现银行信息提交
	CommitWithdrawBankInfo(ctx context.Context, req *api.CommitWithdrawBankInfoReq) error

	// 提现银行信息显示
	WithdrawBankList(ctx context.Context) ([]api.WithdrawBankListRes, error)

	// 代理商提现记录
	AgentWithdrawList(ctx context.Context, req *api.AgentWithdrawListReq) (*page.Collection[*api.AgentWithdrawListRes], error)
}

type commissionSrv struct {
}

func NewCommissionSrv() ICommissionSrv {
	return &commissionSrv{}
}

// 分佣列表
func (c *commissionSrv) CommissionList(ctx context.Context, req *api.CommissionListReq) (*page.Collection[*api.CommissionListRes], error) {
	var (
		account    string
		err        error
		total      int
		resultList []*api.CommissionListRes
	)

	account = ctx.Value("Account").(string)

	collectionDto := &page.Collection[*api.CommissionListRes]{}
	collectionDto.Page = uint64(req.PageNo)
	collectionDto.PageSize = uint64(req.PageSize)

	mod := global.GFDB.Ctx(ctx).Schema("fx").Model("fx.ifcgate_commission_record iec")
	mod.LeftJoin("fx.ifcgate_enterprise_account_apply imvi", "imvi.account=iec.account")
	mod.Fields("iec.trade_no,iec.trade_time,iec.commission_type,iec.trade_amount,iec.trade_currency,iec.commission_amount," +
		"iec.commission_currency,iec.fixed_amount,iec.fixed_currency,imvi.company_name")

	if len(req.TradeNo) > 0 {
		mod.WhereLike("iec.trade_no", "%"+req.TradeNo+"%")
	}
	if len(req.CommissionType) > 0 {
		mod.WhereLike("iec.commission_type", req.CommissionType)
	}
	if len(req.StartTime) > 0 && len(req.EndTime) > 0 {
		mod.Where("iec.created_at >=? and iec.created_at <=?", req.StartTime+" 00:00:00", req.EndTime+" 23:59:59")
	}
	mod.Where("iec.account=?", account)
	mod.Where("iec.account_type='agent'")
	mod.Order("iec.created_at desc")
	mod.Limit(int(page.PageToOffset(uint64(req.PageNo), uint64(req.PageSize))), cast.ToInt(req.PageSize))
	err = mod.ScanAndCount(&resultList, &total, false)
	collectionDto.TotalPage = page.GetTotalPage(uint64(req.PageNo), uint64(req.PageSize), cast.ToInt64(total))
	if err != nil {
		return nil, internalerrors.New(code.ErrUnknown, "数据查询异常")
	}
	collectionDto.Total = cast.ToInt64(total)
	collectionDto.List = resultList

	return collectionDto, err
}

// 代理商佣金账户
func (c *commissionSrv) AgentCommissionAccount(ctx context.Context) ([]*api.AgentCommissionAccountRes, error) {
	type DbVo struct {
		Amount   float64 `json:"amount"`
		Currency string  `json:"currency"`
	}
	var (
		err          error
		account      string
		sqlStr       string
		withdrawList []*model.IfcgateWithdrawRecord
		result       = make([]*api.AgentCommissionAccountRes, 0)
	)
	account = ctx.Value("Account").(string)

	dbList := make([]DbVo, 0)
	sqlStr = "select SUM(a.amount) as amount,a.currency FROM " +
		"(SELECT fixed_amount as amount,fixed_currency as currency FROM ifcgate_commission_record where account=? and budget_sign = 1 and account_type='agent' " +
		"UNION ALL SELECT commission_amount as amount,commission_currency as currency FROM ifcgate_commission_record where account=? and budget_sign = 1 and account_type='agent') " +
		"a where a.currency <>'' GROUP BY a.currency"
	err = global.GFDB.Raw(sqlStr, account, account).Scan(&dbList)

	if err = global.GFDB.Ctx(ctx).Model("ifcgate_withdraw_record").
		Where("account=? and status='success'", account).Scan(&withdrawList); err != nil {
		logger.SugarLogger.Error(err)
		return nil, internalerrors.New(code.ErrUnknown, err.Error())
	}
	currencyMap := make(map[string]float64)
	if len(withdrawList) > 0 {
		for _, value := range withdrawList {
			fAmount := cast.ToFloat64(value.Amount)
			if _, ok := currencyMap[value.Currency]; !ok {
				currencyMap[value.Currency] = fAmount
			} else {
				tAmount := currencyMap[value.Currency]
				currencyMap[value.Currency] = tAmount + value.Amount
			}
		}
	}
	for _, value := range dbList {
		if _, ok := currencyMap[value.Currency]; ok {
			result = append(result, &api.AgentCommissionAccountRes{
				Amount:   cast.ToString(value.Amount - currencyMap[value.Currency]),
				Currency: value.Currency,
			})
		} else {
			result = append(result, &api.AgentCommissionAccountRes{
				Amount:   cast.ToString(value.Amount),
				Currency: value.Currency,
			})
		}
	}
	return result, err
}

// 提现操作
func (c *commissionSrv) WithdrawOperator(ctx context.Context, req *api.WithdrawOperatorReq) error {
	var (
		err                   error
		account               string
		withdrawBankInfo      *model.IfcgateWithdrawBankInfo
		enterpriseAccountInfo *model.IfcgateEnterpriseAccountApply
		redisResult           *gvar.Var
		balance               float64
		redisBalance          float64
		redisAmount           float64
	)

	account = ctx.Value("Account").(string)

	// 查看是否有对应的银行信息
	if err = global.GFDB.Ctx(ctx).Model("ifcgate_withdraw_bank_info").
		Where("account=? and currency=?", account, req.Currency).Scan(&withdrawBankInfo); err != nil {
		logger.SugarLogger.Error(err)
		return internalerrors.New(code.ErrUnknown, err.Error())
	}

	if err = global.GFDB.Ctx(ctx).Model("ifcgate_enterprise_account_apply").
		Where("account=?", account).Scan(&enterpriseAccountInfo); err != nil {
		logger.SugarLogger.Error(err)
		return internalerrors.New(code.ErrUnknown, err.Error())
	}

	if withdrawBankInfo == nil {
		return internalerrors.New(code.ErrUnknown, "代理商没有该币种的提现银行信息")
	}

	redisResult, err = g.Redis().Get(ctx, account+"-"+req.Currency)
	if err != nil {
		logger.SugarLogger.Error(err)
		return internalerrors.New(code.ErrUnknown, err.Error())
	}
	if redisResult.Val() != nil {
		// 说明之前有一笔提现
		redisAmount = redisResult.Float64()
		balance, err = AgentCommissionCurrencyAmount(account, req.Currency)
		if cast.ToFloat64(req.Amount) > balance-redisAmount {
			return internalerrors.New(code.ErrUnknown, fmt.Sprintf("以有%4.f %s 的提现还未处理，本次提现余额不足", redisAmount, req.Currency))
		}
	} else {
		balance, err = AgentCommissionCurrencyAmount(account, req.Currency)
		if cast.ToFloat64(req.Amount) > balance {
			return internalerrors.New(code.ErrUnknown, "提现余额不足")
		}
	}
	redisBalance = redisAmount + cast.ToFloat64(req.Amount)

	// 放入到缓存
	if _, err = g.Redis().Set(ctx, account+"-"+req.Currency, redisBalance); err != nil {
		logger.SugarLogger.Error(err)
		return internalerrors.New(code.ErrUnknown, err.Error())
	}
	if _, err = global.GFDB.Insert(ctx, "ifcgate_withdraw_record", &model.IfcgateWithdrawRecord{
		Account:     account,
		CompanyName: enterpriseAccountInfo.CompanyName,
		Amount:      cast.ToFloat64(req.Amount),
		Currency:    req.Currency,
		Status:      "init",
	}); err != nil {
		logger.SugarLogger.Error(err)
		return internalerrors.New(code.ErrUnknown, err.Error())
	}
	return err
}

// 提现银行信息提交
func (c *commissionSrv) CommitWithdrawBankInfo(ctx context.Context, req *api.CommitWithdrawBankInfoReq) error {
	var (
		account string
		err     error
	)
	account = ctx.Value("Account").(string)
	// 删除之前的
	if _, err = global.GFDB.Ctx(ctx).Model("ifcgate_withdraw_bank_info").Where("account=?", account).Delete(); err != nil {
		logger.SugarLogger.Error(err)
		return internalerrors.New(code.ErrUnknown, err.Error())
	}
	for _, value := range req.CommitWithdrawBankInfo {
		if _, err = global.GFDB.Ctx(ctx).Model("ifcgate_withdraw_bank_info").Insert(&model.IfcgateWithdrawBankInfo{
			Currency: value.Currency,
			Image:    value.Image,
			Account:  account,
		}); err != nil {
			logger.SugarLogger.Error(err)
			return internalerrors.New(code.ErrUnknown, err.Error())
		}
	}
	return err
}

// 提现银行信息显示
func (c *commissionSrv) WithdrawBankList(ctx context.Context) ([]api.WithdrawBankListRes, error) {
	var (
		err     error
		account string
		result  = make([]api.WithdrawBankListRes, 0)
	)
	account = ctx.Value("Account").(string)

	if err = global.GFDB.Ctx(ctx).Model("ifcgate_withdraw_bank_info").
		Where("account=?", account).Scan(&result); err != nil {
		logger.SugarLogger.Error(err)
		return nil, internalerrors.New(code.ErrUnknown, err.Error())
	}
	return result, err
}

// 代理商提现记录
func (c *commissionSrv) AgentWithdrawList(ctx context.Context, req *api.AgentWithdrawListReq) (*page.Collection[*api.AgentWithdrawListRes], error) {
	var (
		err        error
		total      int
		account    string
		resultList []*api.AgentWithdrawListRes
	)

	account = ctx.Value("Account").(string)

	collectionDto := &page.Collection[*api.AgentWithdrawListRes]{}
	collectionDto.Page = uint64(req.PageNo)
	collectionDto.PageSize = uint64(req.PageSize)

	mod := global.GFDB.Ctx(ctx).Schema("fx").Model("fx.ifcgate_withdraw_record")

	mod.Where("account=?", account)
	mod.Order("created_at desc")
	mod.Limit(int(page.PageToOffset(uint64(req.PageNo), uint64(req.PageSize))), cast.ToInt(req.PageSize))
	err = mod.ScanAndCount(&resultList, &total, false)
	collectionDto.TotalPage = page.GetTotalPage(uint64(req.PageNo), uint64(req.PageSize), cast.ToInt64(total))
	if err != nil {
		return nil, internalerrors.New(code.ErrUnknown, "数据查询异常")
	}
	collectionDto.Total = cast.ToInt64(total)
	collectionDto.List = resultList
	return collectionDto, err
}

// 指定查询代理商提现币种余额
func AgentCommissionCurrencyAmount(account, currency string) (float64, error) {
	type DbVo struct {
		Amount   float64 `json:"amount"`
		Currency string  `json:"currency"`
	}
	var (
		err          error
		sqlStr       string
		finalAmount  float64
		withdrawList []*model.IfcgateWithdrawRecord
	)

	dbObj := &DbVo{}
	sqlStr = "select SUM(a.amount) as amount,a.currency FROM " +
		"(SELECT fixed_amount as amount,fixed_currency as currency FROM ifcgate_commission_record where account=? and budget_sign = 1 and account_type='agent' " +
		"UNION ALL SELECT commission_amount as amount,commission_currency as currency FROM ifcgate_commission_record where account=? and budget_sign = 1 and account_type='agent') " +
		"a where a.currency <>'' and a.currency=? GROUP BY a.currency"
	err = global.GFDB.Raw(sqlStr, account, account, currency).Scan(&dbObj)

	if err = global.GFDB.Model("ifcgate_withdraw_record").
		Where("account=? and status='success' and currency=?", account, currency).Scan(&withdrawList); err != nil {
		logger.SugarLogger.Error(err)
		return 0, internalerrors.New(code.ErrUnknown, err.Error())
	}
	currencyMap := make(map[string]float64)
	if len(withdrawList) > 0 {
		for _, value := range withdrawList {
			fAmount := cast.ToFloat64(value.Amount)
			if _, ok := currencyMap[value.Currency]; !ok {
				currencyMap[value.Currency] = fAmount
			} else {
				tAmount := currencyMap[value.Currency]
				currencyMap[value.Currency] = tAmount + value.Amount
			}
		}
	}
	if _, ok := currencyMap[dbObj.Currency]; ok {
		finalAmount = dbObj.Amount - currencyMap[dbObj.Currency]
	} else {
		finalAmount = dbObj.Amount
	}
	return finalAmount, err
}
